<template>
  <div id="app_container">
    <!-- 标题组件 -->
    <Title></Title>
    <!-- 中间视图 -->
    <div id="my_view">
      <!-- 聊天列表视图 -->
      <div id="chat_list" v-show="navActiveChat">
        <!-- 聊天对象列表 -->
        <div class="chat_item" v-for="(item, index) of chatList" :key="index" @click="toDetailsPage(item)">
          <div id="chat_item_left">
            <!-- 左侧图片 -->
            <img :src="item.img" alt="" srcset="">
          </div>
          <div id="chat_item_right">
            <!-- 右侧文本 -->
            <div class="receiver_name_box">
              <div class="receiver_name">{{ item.name }}</div>
              <div class="receiver_time">{{ item.time }}</div>
            </div>
            <div class="last_message_text">{{ item.lastMsg }}</div>
          </div>
        </div>
      </div>
      <!-- 联系人视图 -->
      <div id="contact_list" v-show="!navActiveChat">
        <!-- 添加好友 -->
        <div id="add_box" class="funcBtn" @click="toFunctionPage('addF')">
          <img src="../public/contact/addFriend.png" alt="" srcset="">
          <div>搜索好友/群组</div>
        </div>
        <!-- 通知按钮 -->
        <div id="notice_box" class="funcBtn" @click="toFunctionPage('notice')">
          <img :src="'../public/contact/' + notice_icon + '.png'" alt="" srcset="" id="notice_img_box">
          </img>
          <div>通知</div>
        </div>
        <!-- 群组列表按钮 -->
        <div id="group_box" class="funcBtn" @click="toFunctionPage('group')">
          <img src="../public/contact/group.png" alt="" srcset="">
          <div>群组列表</div>
        </div>
        <!-- 好友列表 -->
        <div id="friends_box">
          <div class="friend_item" v-for="(item, index) of friends" :key="index" @click="intoChatPage(item)">
            <div class="friend_image"><img :src="item.picture" alt="头像" srcset=""></div>
            <div class="friend_info">
              <div class="friend_name">{{ item.name }}</div>
              <div class="friend_email">{{ item.email }}</div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <!-- 底部导航 -->
    <Nav></Nav>
  </div>
</template>

<script setup>
import { onMounted, ref, onBeforeUnmount, reactive, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { getValueBykey, deleteToken, saveValue, getLoginUserId } from "./indexDB/dbKV";
import { addHistoryData, getChatObjectList, getLastRecord, batchAddHistory, getEndMassageByreceiverId, getEndMessagePrivate } from "./indexDB/dbHistory";
import axios from "../public/axiosConfig.js"
import Title from "./components/Title.vue"
import Nav from "./components/Nav.vue"
import { useCommonState } from "./store/commonState.js"
import { formatTimestamp } from "./utils/timeUtil.js"

// 实例化Pinia自定义sotore
const commonStore = useCommonState()

// websocket连接对象
const socket = ref();
// 聊天对象列表
let chatList = ref([]);
// 导航激活标识（chat - true 或 contact - false）
let navActiveChat = ref(true)
// 好友列表
let friends = ref([]);

// 通知图标地址 - 有消息显示右上角红点的图标-代表有消息通知
let notice_icon = ref("notice"); // 红点：notice_red

// 消息格式封装
let messageObj = reactive({
  fromUserId: "", // 从哪来（用户id）
  toId: "", // 到哪去（用户id 或 群组id）
  messageType: "", // 消息类型（public, group, person）
  content: "", // 消息内容
  groupName: "" //群组名称，私聊可为空
})

onMounted(() => {
  // 连接websocket
  connectionWebsocker();
})

// 监听导航组件中的切换导航项
watch(() => commonStore.selectedNav,
  (newValue, oldValue) => {
    if (newValue == "chat") {
      navActiveChat.value = true;
    } else {
      navActiveChat.value = false;
    }
  }
)

// 随机获取一张头像 
async function randamGetImg() {
  let imgs = await getValueBykey("myPictures");
  let randomIndex = Math.floor(Math.random() * imgs.length);
  return imgs[randomIndex];
}

// 点击指定好友，进入聊天页面
async function intoChatPage(userInfo) {
  // 构造chat_receiver对象，存入indexDB，供聊天页面查询聊天记录
  let receiverInfo = { receiverId: userInfo.userId, name: userInfo.name, img: userInfo.picture };
  await saveValue("chat_receiver", JSON.stringify(receiverInfo));

  // 页面跳转
  window.location.href = "/details/";
}

// 【联系】页面功能性跳转 - 传入页面名称
function toFunctionPage(pageName) {
  window.location.href = `/${pageName}/`
}

// 跳转聊天页面，将接收者ID存入indexDB中
async function toDetailsPage(chatInfo) {
  // console.log("点击聊天对象：", chatInfo);
  // 操作indexDB
  await saveValue("chat_receiver", JSON.stringify(chatInfo));
  // console.log(getValueBykey("chat_receiver"), "++++");
  // 页面跳转
  window.location.href = "/details/";
}

// 页面加载，先通过indexDB获取本地消息做展示，然后再向数据库获取最新获取做同步
// 同步策略：通过对比保存的历史记录时间戳，取出数据库中数据大于本地数据时间戳的记录，返回给前端做增量添加
async function initMessageHandler() {
  chatList.value = []
  // 获取本地数据，分拣出聊天对象的ID列表
  await getChatObjectList()
  // 构造请求参数 
  let paramList = [];
  let ids = await getValueBykey('chat-ids');

  for (let id of ids) { paramList.push(id) };

  // 根据id列表获取聊天对象信息
  const res = await axios.post("/groupInfos/getReceiverInfo", paramList);

  // console.log("聊天对象id", paramList);
  // console.log("聊天对象列表:", res);

  // 构造聊天对象列表list[{receiverId:"接收者ID", name:"昵称"},{...}...]
  for (let id of paramList) {
    let imgS = await randamGetImg(); // 随机获取图片

    // 判断ID的类型，从而调用不同的获取最后一条聊天记录方法
    let isUser = await checkUserType(id);
    let lastChatMessage = {};
    if (isUser) {
      // 用户类型
      lastChatMessage = await getEndMessagePrivate(id);
    } else {
      lastChatMessage = await getEndMassageByreceiverId(id) // 获取该聊天对象的最后一条消息
    }

    if (lastChatMessage == null) {
      return 1;
    }
    let time = formatTimestamp(lastChatMessage.timestamp)
    chatList.value.push({ receiverId: id, name: res.data[id], img: imgS, lastMsg: lastChatMessage.message, time: time });

  }
  // == 同步历史消息记录 == 
  synchroData()
}

// 同步数据函数
async function synchroData() {
  // 传入当前用户id和最后一条本地聊天记录的时间戳，对比获取未同步的增量数据
  // 如果本地记录为空，则获取所有聊天记录
  let lastRecordData = await getLastRecord();
  let timestamp = 0;
  if (lastRecordData == null) {
    timestamp = 0;
  } else {
    timestamp = lastRecordData.timestamp;
  }

  let loginUser = await getValueBykey("userInfo")
  // 发送参数获取需要增量同步的数据
  const res = await axios.get(`/historyMessagess/increment/${loginUser.userId}/${timestamp}`)
  // console.log("同步的数据：", res);
  // 同步数据到indexDB 以及 检查聊天列表是否需要更新
  if (res.data.data.length != 0) {
    batchAddHistory(res.data.data);
    // 实时更新聊天对象列表
    updateChatList(res.data.data);
  } else {
    // console.log("不需要同步数据");
  }
}

// 检查聊天列表是否需要更新
// incrementD: 增量数据-历史记录对象
async function updateChatList(incrementD) {

  // 获取当前登录用户ID
  let loginUserId = await getLoginUserId();

  let imgS = await randamGetImg();
  // 提取已有的 receiverId 列表
  const existingReceiverIds = new Set(chatList.value.map(item => item.receiverId));

  // 遍历后端返回的数据，找出不存在于已有 receiverId 集合中的 receiver
  const newReceivers = new Set();
  for (let item of incrementD) {
    if (!existingReceiverIds.has(item.receiver) && item.receiver != loginUserId) {
      // 如果 receiver 不在已有数据中，并且接收者不是当前登录用户ID，则添加到新接收者列表
      newReceivers.add(item.receiver);
    }
  }

  if (newReceivers.length == 0) {
    // console.log("不需要更新聊天对象列表");
    return 1;
  }

  // 根据需要添加聊天对象的id，回溯历史信息对象，找到此聊天对象是私人还是群组
  newReceivers.forEach(receiver => {
    // 查找与 receiver 匹配的聊天对象属性（如群组名）
    const needUpdateObject = incrementD.find(item => item.receiver === receiver);
    // 如果是群组，直接获取对象中的群组名称，构成聊天对象列表数据
    if (needUpdateObject.msgType == "group" || needUpdateObject.msgType == "public") {
      let time = formatTimestamp(needUpdateObject.timestamp)
      chatList.value.push({ receiverId: receiver, name: needUpdateObject.groupName, img: imgS, lastMsg: needUpdateObject.message, time: time })
    } else {
      // 如果是私人聊天，则需要根据此接收者ID查询缓存中接收者名称
      getNameByReceiverId(receiver);
    }
  })

}

// 根据用户Id查询该用户的名称
async function getNameByReceiverId(receiverId) {
  let imgS = await randamGetImg();
  let lastChatMessage = await getEndMassageByreceiverId(receiverId) // 获取该聊天对象的最后一条消息
  let time = formatTimestamp(lastChatMessage.timestamp)
  const res = await axios.get(`/common/getNameByReceiverId?receiverId=${receiverId}`)
  chatList.value.push({ receiverId: receiverId, name: res.data, img: imgS, lastMsg: lastChatMessage.message, time: time })
}

// 构造消息对象
async function createMessage(toId, msgType, content, groupName) {
  let userInfo = await getValueBykey("userInfo");
  messageObj.fromUserId = userInfo.userId;
  messageObj.toId = toId;
  messageObj.messageType = msgType;
  messageObj.content = content;
  messageObj.groupName = groupName;
}

// 检查ID是否为用户ID 
async function checkUserType(userId) {
  const { data: res } = await axios(`/userInfos/checkId?userId=${userId}`);
  return res;
}

// 发送消息-测试
async function sendMessage() {
  await createMessage("maohe101", "public", "我是公共群发消息", "公共群组");
  socket.value.send(JSON.stringify(messageObj));
}

// websocket连接-配置类
async function connectionWebsocker() {
  // 取出登录后的 token 信息，用于 WebSocket 的验证连接
  const token = await getValueBykey("token")// 假设 token 保存在 localStorage 中
  socket.value = new WebSocket(`ws://localhost:8889/chat?token=${token}`);

  // 监控 WebSocket 状态
  socket.value.onopen = () => {
    // console.log('连接socket成功');

    // ===== websocket连接成功 =======

    // 获取本地数据，及数据同步
    initMessageHandler();

    // 获取当前用户的【好友申请】列表
    getFriendApplyList();
    // 获取好友列表
    getFriends();
  };

  socket.value.onclose = (event) => {
    if (event.wasClean) {
      // console.log(`WebSocket 连接已关闭，状态码：${event.code}，原因：${event.reason}`);
      returnLoginPage(0);
    } else {
      // console.error('WebSocket 连接意外关闭');
      returnLoginPage(1)
    }
  };

  socket.value.onerror = (error) => {
    // console.error('WebSocket 连接错误', error);
    returnLoginPage(1)
  };

  // 接收消息
  socket.value.onmessage = async (event) => {
    // 将收到的消息（一条历史记录）转为对象
    let historyO = JSON.parse(event.data);
    // 将消息动态添加到页面显示
    // console.log(`收到${historyO.sender}用户的消息：${historyO.message}`);
    // 将接收到的数据存入IndexDB，作本地持久化
    await addHistoryData(historyO);

    // 更新页面最后一条聊天记录
    await initMessageHandler();

    // 存储当前聊天列表所有ID
    let reIds = new Set()

    // 检查此消息是否存在于聊天对象列表中，不存在则添加（排除接收者为当前登录者）
    for (let chatO of chatList.value) {
      reIds.add(chatO.receiverId)
    }

    if (reIds.has(historyO.receiver)) {
      return 1;
    }

    // 获取登录用户ID
    let loginUserID = await getLoginUserId();
    // 如果接收者为自己，也不需要动态添加到聊天列表
    if (historyO.receiver == loginUserID) {
      return 1;
    }

    let imgS = await randamGetImg();
    if (historyO.msgType == "group" || historyO.msgType == "public") {
      let time = formatTimestamp(historyO.timestamp)
      chatList.value.push({ receiverId: historyO.receiver, name: historyO.groupName, img: imgS, lastMsg: historyO.message, time: time })
    } else {
      // 如果是私人聊天，则需要根据此接收者ID查询缓存中接收者名称
      getNameByReceiverId(historyO.receiver);
    }
  };
}

// 出现连接错误，跳转到登录页
function returnLoginPage(errorStatus) {
  if (errorStatus == 0) {
    ElMessage({
      message: '登录状态异常，请重新登录！',
      type: 'error',
    });
  } else {
    ElMessage({
      message: '登录超时，请重新登录',
      type: 'info',
    });
  }

  setTimeout(() => {
    window.location.href = "/login/"
  }, 500)
}

// 获取好友列表
async function getFriends() {
  // 获取当前登录用户ID
  let userId = await getLoginUserId();
  const { data: res } = await axios.get(`/friendss/getFriendsInfoByUserId/${userId}`);

  // console.log("好友列表：", res);

  if(res.code == 0 || res.data == null){
    return 1;
  }

  // 动态给好友绑定头像
  for (let item of res.data) {
    item['picture'] = await randamGetImg();
  }

  // 赋值显示好友信息列表
  friends.value = res.data;
}


// 获取好友申请列表
async function getFriendApplyList() {
  // 取出当前用户ID
  let userInfo = await getValueBykey("userInfo");

  let userId = userInfo.userId;

  // 调用后端接口，查询申请列表
  const { data: res } = await axios.get(`/friendss/getApplyFriendsInfo/${userId}`);

  if (res.code == 0) {
    // showMessage("info", res.msg)
    // console.log(res.msg);
    return 1;
  }

  // 查询到好友申请，改变【通知】图标
  notice_icon.value = "notice_red";
}

// 在组件卸载前关闭 WebSocket 连接
onBeforeUnmount(() => {
  if (socket.value) {
    socket.value.close();
  }
});

// 通用消息提示函数
function showMessage(messageType, messageText) {
  ElMessage({
    message: messageText,
    type: messageType,
  })
}

</script>

<style scoped>
#app_container {
  max-width: 700px;
  /* margin: 0 auto; */
}

#my_view {
  /* border: solid red 1px; */
  position: relative;
  top: 50px;
  padding-bottom: 50px;
}

.chat_item {
  padding: 10px 10px;
  border-bottom: solid 1px #dddddd;
  /* margin-top: 5px; */
  display: flex;
  flex-direction: row;
  position: relative;
}

#chat_item_left {
  width: 13%;
}

#chat_item_left img {
  width: 45px;
  height: 45px;
  border-radius: 5px;
}

#chat_item_right {
  padding-left: 10px;
  width: 87%;
}

.last_message_text {
  color: #959595;
  font-size: 14px;
  position: relative;
  top: 3px;
  width: 68%;
  text-overflow: ellipsis;
  /* border: solid red 1px; */
  white-space: nowrap;
  overflow: hidden;
}

.receiver_name {
  font-weight: 600;
}

.receiver_name_box {
  display: flex;
  justify-content: space-between;
  width: 100%;
}

.receiver_time {
  color: #959595;
  font-size: 14px;
}

.nav_icon {
  width: 40px;
}

.funcBtn {
  /* border: solid red 1px; */
  display: flex;
  justify-content: left;
  align-items: center;
  padding: 10px 5px;
  /* border-radius: 5px; */
  border-bottom: #dddddd 1px solid;
  font-size: 15px;
}

.funcBtn img {
  width: 36px;
  /* background-color: #723b3b; */
  border-radius: 5px;
}

.funcBtn div {
  position: relative;
  left: 8px;
}

#friends_box {}

.friend_image img {
  width: 43px;
  border-radius: 10px;
}

.friend_info {
  margin-left: 10px;
  font-size: 13px;
  color: #313131;
}

.friend_email {
  padding-top: 2px;
}

.friend_name {
  font-weight: 600;
  font-size: 15px;
  padding-top: 2px;
}

.friend_item {
  display: flex;
  flex-direction: row;
  margin-top: 10px;
  border-bottom: solid 1px #d5d4d4;
  padding: 3px 0px;
}
</style>
